﻿// Copyright (c)  YISH. All rights reserved.
// Licensed under the MIT License, See License.txt in the project root for license information.

using System;
using System.Diagnostics.CodeAnalysis;
using Antlr4.Runtime;
using NSQL.Expressions;
using NSQL.Extensions;
using NSQL.Parser;
using NSQL.Parser.Grammars;
using NSQL.Statements;

namespace NSQL
{
    [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
    public static class SqlParser
    {
        public static string TranslateToSql(string sql)
        {
            return Parse(sql)?.ToSql();
        }
        public static string TranslateToNpgsql(string sql)
        {
            return Parse(sql)?.ToNpgsql();
        }
        public static string TranslateToOracle(string sql)
        {
            return Parse(sql)?.ToOracle();
        }
        public static string TranslateToMySql(string sql)
        {
            return Parse(sql)?.ToMySql();
        }
        public static string TranslateToSqlServer(string sql)
        {
            return Parse(sql)?.ToSqlServer();
        }
        public static string TranslateToSQLite(string sql)
        {
            return Parse(sql)?.ToSQLite();
        }

        public static ISqlObject Parse(string sql)
        {
            return TryParse<ISqlObject>(sql, out var value) ? value : null;
        }
        
        public static IStatement ParseStatement(string statement)
        {
            return TryParse(statement, out IStatement value) ? value : null;
        }
        
        public static IExpression ParseExpression(string expression)
        {
            return TryParse(expression, out IExpression value) ? value : null;
        }

        public static IPredicateExpression ParsePredicateExpression(string expression)
        {
            return TryParse(expression, out IPredicateExpression value) ? value : null;
        }

        public static bool TryParse<T>(string sql, out T value) where T : ISqlObject
        {
            value = default;
            if (string.IsNullOrWhiteSpace(sql)) return false;
            var parser = new NSqlParser(new CommonTokenStream(new NSqlLexer(new AntlrInputStream(sql))));
            var context = parser.parse();
            if (parser.NumberOfSyntaxErrors > 0)
            {
                return false;
            }

            value = (T) new NSqlGrammarVisitor().VisitParse(context);
            return true;
        }
        
        public static bool TryParse(string sql, out IPredicateExpression value)
        {
            value = default;
            if (string.IsNullOrWhiteSpace(sql)) return false;
            if (sql.Trim().Equals(EmptyExpression.Instance.ToString(), StringComparison.OrdinalIgnoreCase))
            {
                value = EmptyExpression.Instance;
                return true;
            }
            var parser = new NSqlParser(new CommonTokenStream(new NSqlLexer(new AntlrInputStream(sql))));
            var context = parser.logical_expression();
            if (parser.NumberOfSyntaxErrors > 0)
            {
                return false;
            }

            value = (IPredicateExpression) new NSqlGrammarVisitor().VisitLogical_expression(context);
            return true;
        }
        
        public static bool TryParse(string sql, out IExpression value)
        {
            value = default;
            if (string.IsNullOrWhiteSpace(sql)) return false;
            if (sql.Trim().Equals(EmptyExpression.Instance.ToString(), StringComparison.OrdinalIgnoreCase))
            {
                value = EmptyExpression.Instance;
                return true;
            }
            var parser = new NSqlParser(new CommonTokenStream(new NSqlLexer(new AntlrInputStream(sql))));
            var context = parser.expression();
            if (parser.NumberOfSyntaxErrors > 0)
            {
                return false;
            }

            value = (IExpression) new NSqlGrammarVisitor().VisitExpression(context);
            return true;
        }

        public static bool TryParse(string sql, out IStatement value)
        {
            value = default;
            if (string.IsNullOrWhiteSpace(sql)) return false;
            var parser = new NSqlParser(new CommonTokenStream(new NSqlLexer(new AntlrInputStream(sql))));
            var context = parser.unit_statement();
            if (parser.NumberOfSyntaxErrors > 0)
            {
                return false;
            }

            value = (IStatement) new NSqlGrammarVisitor().VisitUnit_statement(context);
            return true;
        }

        public static bool TestSyntax(string sql)
        {
            var parser = new NSqlParser(
                new CommonTokenStream(new NSqlLexer(new AntlrInputStream(sql))));
            return parser.parse() != null && parser.NumberOfSyntaxErrors == 0;
        }
    }
}